1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 12 module hip.api.internal; 13 import hip.api; 14 15 ///Used for creating a function which will generate an overload to call a function pointer 16 struct Overload 17 { 18 string targetName; 19 } 20 21 version(WebAssembly) version = ErrorOnLoadSymbol; 22 version(PSVita) version = ErrorOnLoadSymbol; 23 24 version(ScriptAPI) version = LoadFunctionPointers; 25 26 27 version(LoadFunctionPointers) 28 { 29 __gshared void* _dll; 30 void initializeHip() 31 { 32 version(ErrorOnLoadSymbol) 33 { 34 assert(false, "Cannot load symbols in this version."); 35 } 36 else 37 { 38 version(Windows){_dll = GetModuleHandle(null);} 39 else 40 { 41 import core.sys.posix.dlfcn:dlopen, RTLD_NOW; 42 _dll = dlopen(null, RTLD_NOW); 43 } 44 import core.stdc.stdio; 45 if(_dll == null) 46 printf("Could not load GetModuleHandle(null)\n"); 47 hipDestroy = cast(typeof(hipDestroy))_loadSymbol(_dll, "hipDestroy"); 48 if(hipDestroy == null) 49 printf("Fatal error: could not load hipDestroy\n"); 50 } 51 } 52 } 53 version(Windows) 54 { 55 @nogc nothrow extern(Windows) 56 { 57 void* GetModuleHandleW(const(wchar)* str); 58 void* GetProcAddress(void* mod, const(char)* func); 59 void* FreeLibrary(void* lib); 60 uint GetLastError(); 61 } 62 alias GetModuleHandle = GetModuleHandleW; 63 alias _loadSymbol = GetProcAddress; 64 } 65 66 version(Posix) 67 { 68 import core.sys.posix.dlfcn:dlsym; 69 alias _loadSymbol = dlsym; 70 } 71 enum bool isFunctionPointer(alias T) = is(typeof(*T) == function); 72 73 /** 74 * Prefer using that function instead of loadSymbol, as compile 75 * time sequences reduced the binary size in almost 100kb. 76 * 77 * The problem is not yet solved, but it is a lot better than doing several 78 * template instantiations 79 */ 80 void loadSymbols(Ts...)() 81 { 82 static foreach(s; Ts) 83 s = cast(typeof(s))_loadSymbol(_dll, s.stringof); 84 } 85 86 /** 87 * This function will load all function pointers defined in the module passed. 88 */ 89 void loadModuleFunctionPointers(alias targetModule, string exportedClass = "")() 90 { 91 string prefix = ""; 92 string importedFunctionName; 93 static if(exportedClass != "") 94 prefix = exportedClass~"_"; 95 static foreach(member; __traits(allMembers, targetModule)) 96 {{ 97 alias f = __traits(getMember, targetModule, member); 98 static if(isFunctionPointer!(f)) 99 { 100 importedFunctionName = prefix~member~'\0'; 101 if(f is null) 102 { 103 f = cast(typeof(f))_loadSymbol(_dll, importedFunctionName.ptr); 104 if(f is null) 105 { 106 import core.stdc.stdio; 107 printf(f.stringof~" wasn't able to load (tried with %s)\n", importedFunctionName.ptr); 108 } 109 } 110 } 111 }} 112 } 113 114 115 string generateFunctionDefinitionFromFunctionPointer(alias funcPointerSymbol, string name)() 116 { 117 import std.traits; 118 string params; 119 string identifiers; 120 121 bool isFirst = true; 122 alias storage = ParameterStorageClassTuple!funcPointerSymbol; 123 static foreach(i, p; Parameters!funcPointerSymbol) 124 { 125 if(!isFirst) 126 { 127 params~= ","; 128 identifiers~= ","; 129 } 130 else 131 isFirst = false; 132 if(storage[i] != ParameterStorageClass.none) 133 params~= storage[i].stringof["ParameterStorageClass.".length..$-1] ~" "; //Remove enum namespace and the "_" 134 params~= p.stringof ~ " _"~i.stringof; 135 identifiers~= "_"~i.stringof; 136 } 137 138 return (ReturnType!funcPointerSymbol).stringof ~ " "~ name ~ "("~params 139 ~"){return "~ funcPointerSymbol.stringof ~ "("~identifiers ~ ");}"; 140 141 } 142 143 mixin template OverloadsForFunctionPointers(alias targetModule) 144 { 145 import std.traits; 146 static foreach(symbol; getSymbolsByUDA!(targetModule, Overload)) 147 { 148 pragma(msg, generateFunctionDefinitionFromFunctionPointer!(symbol, getUDAs!(symbol, Overload)[0].targetName)); 149 mixin(generateFunctionDefinitionFromFunctionPointer!(symbol, getUDAs!(symbol, Overload)[0].targetName)); 150 } 151 } 152 153 mixin template ExpandClassFunctionPointers(alias targetClass) 154 { 155 import hip.api.internal: isFunctionPointer; 156 157 static foreach(mem; __traits(allMembers, targetClass)) 158 { 159 static if(isFunctionPointer!(__traits(getMember, targetClass, mem))) 160 { 161 mixin(__traits(getVisibility, __traits(getMember, targetClass, mem)), " alias ", mem, " = ", __traits(identifier, targetClass), ".", mem,";"); 162 } 163 } 164 } 165 template Flag(string f) 166 { 167 enum Flag : bool 168 { 169 No = false, 170 Yes = true 171 } 172 } 173 174 alias UseExportedClass = Flag!"UseExportedClass"; 175 176 void loadClassFunctionPointers(alias targetClass, 177 UseExportedClass useExported = UseExportedClass.No, 178 string exportedClass = "") 179 () 180 { 181 string prefix = ""; 182 string importedFunctionName; 183 184 version(ErrorOnLoadSymbol) 185 { 186 assert(false, "Cannot load symbols in this version."); 187 } 188 else 189 { 190 string nExportedClass = exportedClass; 191 static if(useExported) 192 { 193 static if(exportedClass == "") 194 nExportedClass = targetClass.stringof; 195 prefix = nExportedClass~"_"; 196 } 197 static foreach(member; __traits(allMembers, targetClass)) 198 {{ 199 alias f = __traits(getMember, targetClass, member); 200 static if(isFunctionPointer!(f)) 201 { 202 importedFunctionName = prefix~member~'\0'; 203 f = cast(typeof(f))_loadSymbol(_dll, importedFunctionName.ptr); 204 if(f is null) 205 { 206 import core.stdc.stdio; 207 printf(f.stringof ~ " wasn't able to load (tried with %s)\n", importedFunctionName.ptr); 208 } 209 } 210 }} 211 } 212 } 213 214 template loadSymbolsFromExportD(string exportedClass, Ts...) 215 { 216 version(ErrorOnLoadSymbol) 217 { 218 enum impl = ""; 219 } 220 else 221 { 222 enum impl = () 223 { 224 enum e = '"'~exportedClass~"_\""; 225 string ret; 226 static foreach(i, s; Ts) 227 { 228 ret~= s.stringof ~"= cast(typeof("~s.stringof~ " ))_loadSymbol(_dll, ("~e~"~\""~s.stringof~"\\0\").ptr);"; 229 if(s.stringof is null) 230 { 231 import core.stdc.stdio; 232 printf("Could not load "~s.stringof~" (tried with "~ e~s.stringof~")\n"); 233 } 234 } 235 return ret; 236 }(); 237 } 238 239 enum loadSymbolsFromExportD = impl; 240 }